using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using DownloadMailTask.POP3Client.Mime;

namespace DownloadMailTask.POP3Client.Mime
{
    /// <summary>
    /// Summary description for Utility.
    /// </summary>
    public class Utility
    {
        private static bool m_blnLog=false;
        private static string m_strLogFile = "OpenPOP.log";

        public Utility()
        {
        }

        //		public static string[] SplitText(string strText, string strSplitter)
        //		{
        //			string []segments=new string[0];
        //			int indexOfstrSplitter=strText.IndexOf(strSplitter);
        //			if(indexOfstrSplitter!=-1)
        //			{
        //
        //			}
        //			return segments;
        //		}
        //

        /// <summary>
        /// Verifies whether the file is of picture type or not
        /// </summary>
        /// <param name="strFile">File to be verified</param>
        /// <returns>True if picture file, false if not</returns>
        public static bool IsPictureFile(string strFile)
        {
            try
            {
                if(strFile!=null&&strFile!="")
                {
                    strFile=strFile.ToLower();
                    if(strFile.EndsWith(".jpg")||strFile.EndsWith(".bmp")||strFile.EndsWith(".ico")||strFile.EndsWith(".gif")||strFile.EndsWith(".png"))
                        return true;
                    else
                        return false;
                }
                else
                    return false;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Parse date time info from MIME header
        /// </summary>
        /// <param name="strDate">Encoded MIME date time</param>
        /// <returns>Decoded date time info</returns>
        public static string ParseEmailDate(string strDate)
        {
            string strRet=strDate.Trim();
            int indexOfTag=strRet.IndexOf(",");
            if(indexOfTag!=-1)
            {
                strRet=strRet.Substring(indexOfTag+1);
            }

            strRet=QuoteText(strRet,"+");
            strRet=QuoteText(strRet,"-");
            strRet=QuoteText(strRet,"GMT");
            strRet=QuoteText(strRet,"CST");
            return strRet.Trim();
        }

        /// <summary>
        /// Quote the text according to a tag
        /// </summary>
        /// <param name="strText">Text to be quoted</param>
        /// <param name="strTag">Quote tag</param>
        /// <returns>Quoted Text</returns>
        public static string QuoteText(string strText, string strTag)
        {
            int indexOfTag=strText.IndexOf(strTag);
            if(indexOfTag!=-1)
                return strText.Substring(0,indexOfTag-1);
            else
                return strText;
        }

        /// <summary>
        /// Parse file name from MIME header
        /// </summary>
        /// <param name="strHeader">MIME header</param>
        /// <returns>Decoded file name</returns>
        public static string ParseFileName(string strHeader)
        {
            string strTag;
            strTag="filename=";
            int intPos=strHeader.ToLower().IndexOf(strTag);
            if(intPos==-1)
            {
                strTag="name=";
                intPos=strHeader.ToLower().IndexOf(strTag);
            }
            string strRet;
            if(intPos!=-1)
            {
                strRet=strHeader.Substring(intPos+strTag.Length);
                intPos=strRet.ToLower().IndexOf(";");
                if(intPos!=-1)
                    strRet=strRet.Substring(1,intPos-1);
                strRet=RemoveQuote(strRet);
            }
            else
                strRet="";

            return strRet;
        }

        /// <summary>
        /// Parse email address from MIME header
        /// </summary>
        /// <param name="strEmailAddress">MIME header</param>
        /// <param name="strUser">Decoded user name</param>
        /// <param name="strAddress">Decoded email address</param>
        /// <returns>True if decoding succeeded, false if failed</returns>
        public static bool ParseEmailAddress(string strEmailAddress,ref string strUser, ref string strAddress)
        {
            int indexOfAB=strEmailAddress.Trim().LastIndexOf("<");
            int indexOfEndAB=strEmailAddress.Trim().LastIndexOf(">");
            strUser=strEmailAddress;
            strAddress=strEmailAddress;
            if(indexOfAB>=0&&indexOfEndAB>=0)
            {
                if(indexOfAB>0)
                {
                    strUser=strUser.Substring(0,indexOfAB-1);
                    //					strUser=strUser.Substring(0,indexOfAB-1).Trim('\"');
                    //					if(strUser.IndexOf("\"")>=0)
                    //					{
                    //						strUser=strUser.Substring(1,strUser.Length-1);
                    //					}
                }
                strUser=strUser.Trim();
                strUser=strUser.Trim('\"');
                strAddress=strAddress.Substring(indexOfAB+1,indexOfEndAB-(indexOfAB+1));
            }
            strUser=strUser.Trim();
            strUser=DecodeText(strUser);
            strAddress=strAddress.Trim();

            return true;
        }

        /// <summary>
        /// Save byte content to a file
        /// </summary>
        /// <param name="strFile">File to be saved to</param>
        /// <param name="bytContent">Byte array content</param>
        /// <returns>True if saving succeeded, false if failed</returns>
        public static bool SaveByteContentToFile(string strFile,byte[] bytContent)
        {
            try
            {
                if(File.Exists(strFile))
                    File.Delete(strFile);
                FileStream fs=File.Create(strFile);
                fs.Write(bytContent,0,bytContent.Length);
                fs.Close();
                return true;
            }
            catch(Exception e)
            {
                LogError("SaveByteContentToFile():"+e.Message);
                return false;
            }
        }

        /// <summary>
        /// Save text content to a file
        /// </summary>
        /// <param name="strFile">File to be saved to</param>
        /// <param name="strText">Text content</param>
        /// <param name="blnReplaceExists">Replace file if exists</param>
        /// <returns>True if saving succeeded, false if failed</returns>
        public static bool SavePlainTextToFile(string strFile, string strText, bool blnReplaceExists)
        {
            try
            {
                bool blnRet=true;

                if(File.Exists(strFile))
                {
                    if(blnReplaceExists)
                        File.Delete(strFile);
                    else
                        blnRet=false;
                }

                if(blnRet==true)
                {
                    StreamWriter sw=File.CreateText(strFile);
                    sw.Write(strText);
                    sw.Close();
                }

                return blnRet;
            }
            catch(Exception e)
            {
                LogError("SavePlainTextToFile():"+e.Message);
                return false;
            }
        }

        /// <summary>
        /// Read text content from a file
        /// </summary>
        /// <param name="strFile">File to be read from</param>
        /// <param name="strText">Read text content</param>
        /// <returns>True if reading succeeded, false if failed</returns>
        public static bool ReadPlainTextFromFile(string strFile, ref string strText)
        {
            if(File.Exists(strFile))
            {
                StreamReader fs=new StreamReader(strFile);
                strText=fs.ReadToEnd();
                fs.Close();
                return true;
            }
            else
                return false;
        }

        /// <summary>
        /// Sepearte header name and header value
        /// </summary>
        /// <param name="strRawHeader"></param>
        /// <returns></returns>
        public static string[] GetHeadersValue(string strRawHeader)
        {
            if(strRawHeader==null)
                throw new ArgumentNullException("strRawHeader","Argument was null");

            string []array=new string[2]{"",""};
            int indexOfColon=strRawHeader.IndexOf(":");			

            try
            {
                array[0]=strRawHeader.Substring(0,indexOfColon).Trim();
                array[1]=strRawHeader.Substring(indexOfColon+1).Trim();
            }
            catch(Exception){}

            return array;
        }

        /// <summary>
        /// Get quoted text
        /// </summary>
        /// <param name="strText">Text with quotes</param>
        /// <param name="strSplitter">Splitter</param>
        /// <param name="strTag">Target tag</param>
        /// <returns>Text without quote</returns>
        public static string GetQuotedValue(string strText, string strSplitter, string strTag)
        {
            if(strText==null)
                throw new ArgumentNullException("strText","Argument was null");

            string []array=new string[2]{"",""};
            int indexOfstrSplitter=strText.IndexOf(strSplitter);			

            try
            {
                array[0]=strText.Substring(0,indexOfstrSplitter).Trim();
                array[1]=strText.Substring(indexOfstrSplitter+1).Trim();
                int pos=array[1].IndexOf("\"");
                if(pos!=-1)
                {
                    int pos2=array[1].IndexOf("\"",pos+1);
                    array[1]=array[1].Substring(pos+1,pos2-pos-1);
                }
            }
            catch(Exception){}

            //return array;
            if(array[0].ToLower()==strTag.ToLower())
                return array[1].Trim();
            else
                return null;

/*			string []array=null;
			try
			{
				array=Regex.Split(strText,strSplitter);
				//return array;
				if(array[0].ToLower()==strTag.ToLower())
					return RemoveQuote(array[1].Trim());
				else
					return null;
			}
			catch
			{return null;}*/
        }

        /// <summary>
        /// Change text encoding
        /// </summary>
        /// <param name="strText">Source encoded text</param>
        /// <param name="strCharset">New charset</param>
        /// <returns>Encoded text with new charset</returns>
        public static string Change(string strText,string strCharset)
        {
            if (strCharset==null || strCharset=="")
                return strText;
            byte[] b=Encoding.Default.GetBytes(strText);
            return new string(Encoding.GetEncoding(strCharset).GetChars(b));
        }

        /// <summary>
        /// Remove non-standard base 64 characters
        /// </summary>
        /// <param name="strText">Source text</param>
        /// <returns>standard base 64 text</returns>
        public static string RemoveNonB64(string strText)
        {
            return strText.Replace("\0","");
        }

        /// <summary>
        /// Remove white blank characters
        /// </summary>
        /// <param name="strText">Source text</param>
        /// <returns>Text with white blanks</returns>
        public static string RemoveWhiteBlanks(string strText)
        {
            return strText.Replace("\0","").Replace("\r\n","");
        }

        /// <summary>
        /// Remove quotes
        /// </summary>
        /// <param name="strText">Text with quotes</param>
        /// <returns>Text without quotes</returns>
        public static string RemoveQuote(string strText)			
        {
            string strRet=strText;
            if(strRet.StartsWith("\""))
                strRet=strRet.Substring(1);
            if(strRet.EndsWith("\""))
                strRet=strRet.Substring(0,strRet.Length-1);
            return strRet;
        }

        /// <summary>
        /// Decode one line of text
        /// </summary>
        /// <param name="strText">Encoded text</param>
        /// <returns>Decoded text</returns>
        public static string DecodeLine(string strText)
        {
            return DecodeText(RemoveWhiteBlanks(strText));
        }

        /// <summary>
        /// Verifies wether the text is a valid MIME Text or not
        /// </summary>
        /// <param name="strText">Text to be verified</param>
        /// <returns>True if MIME text, false if not</returns>
        private static bool IsValidMIMEText(string strText)
        {
            int intPos=strText.IndexOf("=?");
            return (intPos!=-1&&strText.IndexOf("?=",intPos+6)!=-1&&strText.Length>7);
        }

        /// <summary>
        /// Decode text
        /// </summary>
        /// <param name="strText">Source text</param>
        /// <returns>Decoded text</returns>
        public static string DecodeText(string strText)
        {
            /*try
			{
				string strRet="";
				string strBody="";
				MatchCollection mc=Regex.Matches(strText,@"\=\?(?<Charset>\S+)\?(?<Encoding>\w)\?(?<Content>\S+)\?\=");

				for(int i=0;i<mc.Count;i++)
				{
					if(mc[i].Success)
					{
						strBody=mc[i].Groups["Content"].Value;

						switch(mc[i].Groups["Encoding"].Value.ToUpper())
						{
							case "B":
								strBody=deCodeB64s(strBody,mc[i].Groups["Charset"].Value);
								break;
							case "Q":
								strBody=DecodeQP.ConvertHexContent(strBody);//, m.Groups["Charset"].Value);
								break;
							default:
								break;
						}
						strRet+=strBody;
					}
					else
					{
						strRet+=mc[i].Value;
					}
				}
				return strRet;
			}
			catch
			{return strText;}*/

            try
            {
                string strRet="";
                string[] strParts=Regex.Split(strText,"\r\n");
                string strBody="";
                const string strRegEx=@"\=\?(?<Charset>\S+)\?(?<Encoding>\w)\?(?<Content>\S+)\?\=";
                Match m=null;

                for(int i=0;i<strParts.Length;i++)
                {
                    m = Regex.Match(strParts[i], strRegEx);
                    if(m.Success)
                    {
                        strBody=m.Groups["Content"].Value;

                        switch(m.Groups["Encoding"].Value.ToUpper())
                        {
                            case "B":
                                strBody=deCodeB64s(strBody,m.Groups["Charset"].Value);
                                break;
                            case "Q":
                                strBody=DecodeQP.ConvertHexContent(strBody);//, m.Groups["Charset"].Value);
                                break;
                            default:
                                break;
                        }
                        strRet+=strBody;
                    }
                    else
                    {
                        if(!IsValidMIMEText(strParts[i]))
                            strRet+=strParts[i];
                        else
                        {
                            //blank text
                        }
                    }
                }
                return strRet;
            }
            catch
            {return strText;}

/*		
		{
			try
			{
				if(strText!=null&&strText!="")
				{
					if(IsValidMIMEText(strText))
					{
						//position at the end of charset
						int intPos=strText.IndexOf("=?");
						int intPos2=strText.IndexOf("?",intPos+2);
						if(intPos2>3)
						{
							string strCharset=strText.Substring(2,intPos2-2);
							string strEncoding=strText.Substring(intPos2+1,1);
							int intPos3=strText.IndexOf("?=",intPos2+3);
							string strBody=strText.Substring(intPos2+3,intPos3-intPos2-3);
							string strHead="";
							if(intPos>0)
							{
								strHead=strText.Substring(0,intPos-1);
							}
							string strEnd="";
							if(intPos3<strText.Length-2)
							{
								strEnd=strText.Substring(intPos3+2);
							}
							switch(strEncoding.ToUpper())
							{
								case "B":
									strBody=deCodeB64s(strBody);
									break;
								case "Q":
									strBody=DecodeQP.ConvertHexContent(strBody);
									break;
								default:
									break;
							}
							strText=strHead+strBody+strEnd;
							if(IsValidMIMEText(strText))
								return DecodeText(strText);
							else
								return strText;
						}
						else
						{return strText;}
					}
					else
					{return strText;}
				}
				else
				{return strText;}
			}
			catch
			{return strText;}*/
        }
		
        /// <summary>
        /// 
        /// </summary>
        /// <param name="strText"></param>
        /// <returns></returns>
        public static string deCodeB64s(string strText)
        {
            return Encoding.Default.GetString(deCodeB64(strText));
        }
		
        public static string deCodeB64s(string strText,string strEncoding)
        {
            try
            {
                if(strEncoding.ToLower()=="ISO-8859-1".ToLower())
                    return deCodeB64s(strText);
                else
                    return Encoding.GetEncoding(strEncoding).GetString(deCodeB64(strText));
            }
            catch
            {
                return deCodeB64s(strText);
            }
        }
		
        private static byte []deCodeB64(string strText)
        {
            byte[] by=null;
            try
            { 
                if(strText!="")
                {
                    by=Convert.FromBase64String(strText); 
                    //strText=Encoding.Default.GetString(by);
                }
            } 
            catch(Exception e) 
            {
                by=Encoding.Default.GetBytes("\0");
                LogError("deCodeB64():"+e.Message);
            }
            return by;
        }

        /// <summary>
        /// Turns file logging on and off.
        /// </summary>
        /// <remarks>Comming soon.</remarks>
        public static bool Log
        {
            get
            {
                return m_blnLog;
            }
            set
            {
                m_blnLog = value;
            }
        }

        internal static void LogError(string strText) 
        {
            //Log=true;
            if(Log)
            {
                FileInfo file = null;
                FileStream fs = null;
                StreamWriter sw = null;
                try
                {
                    file = new FileInfo(m_strLogFile);
                    sw = file.AppendText();
                    //fs = new FileStream(m_strLogFile, FileMode.OpenOrCreate, FileAccess.Write);
                    //sw = new StreamWriter(fs);
                    sw.WriteLine(DateTime.Now);
                    sw.WriteLine(strText);
                    sw.WriteLine("\r\n");
                    sw.Flush();
                }
                finally
                {
                    if(sw != null)
                    {
                        sw.Close();
                        sw = null;
                    }
                    if(fs != null)
                    {
                        fs.Close();
                        fs = null;
                    }
					
                }
            }
        }

        public static bool IsQuotedPrintable(string strText)
        {
            if(strText!=null)
                return (strText.ToLower()=="quoted-printable".ToLower());
            else
                return false;
        }

        public static bool IsBase64(string strText)
        {
            if(strText!=null)
                return (strText.ToLower()=="base64".ToLower());
            else
                return false;
        }

        public static string[] SplitOnSemiColon(string strText)
        {
            if(strText==null)
                throw new ArgumentNullException("strText","Argument was null");

            string []array=null;
            int indexOfColon=strText.IndexOf(";");			

            if(indexOfColon<0)
            {
                array=new string[1];
                array[0]=strText;
                return array;
            }
            else
            {
                array=new string[2];
            }

            try
            {
                array[0]=strText.Substring(0,indexOfColon).Trim();
                array[1]=strText.Substring(indexOfColon+1).Trim();
            }
            catch(Exception){}

            return array;
        }

        public static bool IsNotNullText(string strText)
        {
            try
            {
                return (strText!=null&&strText!="");
            }
            catch
            {
                return false;
            }
        }

        public static bool IsNotNullTextEx(string strText)
        {
            try
            {
                return (strText!=null&&strText.Trim()!="");
            }
            catch
            {
                return false;
            }
        }

        public static bool IsOrNullTextEx(string strText)
        {
            try
            {
                return (strText==null||strText.Trim()=="");
            }
            catch
            {
                return false;
            }
        }

    }
}